#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <time.h>
#define ERROR_CHECK(ret, num, msg) \
    {                              \
        if (ret == num)            \
        {                          \
            perror(msg);           \
            exit(1);               \
        }                          \
    }
#define ARGS_CHECK(argc, num)                 \
    {                                         \
        if (argc != num)                      \
        {                                     \
            fprintf(stderr, "args error!\n"); \
            return -1;                        \
        }                                     \
    }
char getFileType(__mode_t mode)
{
    if (S_ISDIR(mode))
        return 'd';
    if (S_ISBLK(mode))
        return 'b';
    if (S_ISCHR(mode))
        return 'c';
    if (S_ISFIFO(mode))
        return 'p';
    if (S_ISLNK(mode))
        return 'l';
    if (S_ISSOCK(mode))
        return 's';
    if (S_ISREG(mode))
        return '-';
    return '?';
}

char *get_permissions(__mode_t mode)
{
    static char permissions[10];
    strcpy(permissions, "rwxrwxrwx");
    permissions[9] = '\0';
    for (size_t i = 0; i < 9; i++)
    {
        if (!(mode & 1 << (8 - i))) // mode &100  ; mode & 010 ; mode & 001;
        {
            permissions[i] = '-';
        }
    }

    return permissions;
}
void show(char **p, int index)
{
    for (size_t i = 0; i < index; i++)
    { 
        if (p[i][0] == 'd')
        {
            printf("\033[34m%s\033[0m\n",p[i]);
        }else if (p[i][3] == 'x')
        {
            printf("\033[32m%s\033[0m\n",p[i]);
        }else{
            printf("%s",p[i]);
        }

        
    }
}
int compare(const void *a, const void *b)
{
    return strcmp(*(char **)a, *(char **)b);
}
int main(int argc, char *argv[])
{
    ARGS_CHECK(argc, 2);
    DIR *dirp = opendir(argv[1]);
    ERROR_CHECK(NULL, dirp, "opendir");
    int ret = chdir(argv[1]);
    ERROR_CHECK(ret, -1, "chdir");
    struct dirent *dirpStructure;
    struct stat statBuf;
    int size = 128;
    char **pathlink = (char **)malloc(size * sizeof(char));
    int index = 0;
    char **pathlink1 = (char **)malloc(size * sizeof(char));
    int index1 = 0;
    int seek = telldir(dirp);
    while (dirpStructure = readdir(dirp))
    {
        if (strcmp(dirpStructure->d_name, ".") == 0 || strcmp(dirpStructure->d_name, "..") == 0)
        {
            char *path = (char *)malloc(512 * sizeof(char));
            int ret = stat(dirpStructure->d_name, &statBuf);
            ERROR_CHECK(-1, ret, "stat");
            char file_type = getFileType(statBuf.st_mode);
            struct passwd *uid = getpwuid(statBuf.st_uid);
            struct group *gid = getgrgid(statBuf.st_gid);
            char mtime[20];

            strftime(mtime, sizeof(mtime), "%b %d %H:%M", localtime(&statBuf.st_mtime));
            char *path1 = (char *)malloc(512 * sizeof(char));
            snprintf(path1, 512, "%c%s %2ld %s %s %6ld %s %s\n", file_type,
                     get_permissions(statBuf.st_mode),
                     statBuf.st_nlink,
                     uid->pw_name,
                     gid->gr_name,
                     statBuf.st_size,
                     mtime,
                     dirpStructure->d_name);
            pathlink1[index1++] = path1;
        }
    }
    seekdir(dirp,seek);
    while (dirpStructure = readdir(dirp))
    {
        if (strcmp(dirpStructure->d_name, ".") == 0 || strcmp(dirpStructure->d_name, "..") == 0)
            continue;
        int ret = stat(dirpStructure->d_name, &statBuf);
        ERROR_CHECK(-1, ret, "stat");
        char file_type = getFileType(statBuf.st_mode);
        struct passwd *uid = getpwuid(statBuf.st_uid);
        struct group *gid = getgrgid(statBuf.st_gid);
        char mtime[20];

        strftime(mtime, sizeof(mtime), "%b %d %H:%M", localtime(&statBuf.st_mtime));
        char *path = (char *)malloc(512 * sizeof(char));
        snprintf(path, 512, "%c%s %2ld %s %s %5ld %s %s\n", file_type,
                 get_permissions(statBuf.st_mode),
                 statBuf.st_nlink,
                 uid->pw_name,
                 gid->gr_name,
                 statBuf.st_size,
                 mtime,
                 dirpStructure->d_name);

        pathlink[index++] = path;
        if (index == size - 1)
        {
            size = size * 2;
            pathlink = (char **)realloc(pathlink, size * sizeof(char));
            ERROR_CHECK(NULL, pathlink, "realooc");
        }
    }
    qsort(pathlink, index, sizeof(char *), compare);
    show(pathlink1,index1);
    show(pathlink, index);

    for (int i = 0; i < index; i++)
    {
        free(pathlink[i]);
    }
    free(pathlink);
    puts("");

    return 0;
}